﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using dasBlog.Storage;
using System.Collections.ObjectModel;
using newtelligence.DasBlog.Runtime;
using System.Xml;

namespace dasBlog.Services.Interop
{
    class StorageBusDataService : IBlogDataService
    {
        private ContextUri scopeUri;
        private ContextUri postsUri;
        private ContextUri mediaUri;

        public StorageBusDataService(string scopeName)
        {
            this.scopeUri = new ContextUri(scopeName);
            this.postsUri = new ContextUri(scopeName, PathSegmentName.Posts);
            this.mediaUri = new ContextUri(scopeName, PathSegmentName.Media);
        }

        public Entry GetEntry(string entryId)
        {
            IStorageNode storageNode = StorageBus.Current.FindNode(postsUri);
            TextEntry entry = SerializationTools<TextEntry>.Deserialize(storageNode.Get(null, new ContextUri(postsUri, entryId).ToString(), null));
            if (entry != null)
            {
                return EntryFromTextEntry(entry);
            }
            else
            {
                return null;
            }
        }

        public Entry GetEntryForEdit(string entryId)
        {
            return GetEntry(entryId);
        }

        public EntryCollection GetEntriesForDay(DateTime start, TimeZone tz, string acceptLanguages, int maxDays, int maxEntries, string categoryName)
        {
            IStorageNode storageNode = StorageBus.Current.FindNode(postsUri);
            return new EntryCollection((from entry in SerializationTools<TextEntry>.DeserializeList(
                                            storageNode.Select( null,
                                                                postsUri.ToString(),
                                                                ContextMatch.Exact,
                                                                new DateRangeQueryDescription(DateTime.MinValue, start.Date.ToUniversalTime()),
                                                                null)
                                            )
                          orderby entry.Created descending 
                          where entry.Language == null || acceptLanguages.Contains(entry.Language)
                          select EntryFromTextEntry(entry)).Take(maxEntries).ToArray());
        }

        public EntryCollection GetEntriesForMonth(DateTime summary, TimeZone tz, string acceptLanguages)
        {
            IStorageNode storageNode = StorageBus.Current.FindNode(postsUri);
            return new EntryCollection((from te in SerializationTools<TextEntry>.DeserializeList(
                                                    storageNode.Select(null, postsUri.ToString(), ContextMatch.Exact,
                                                        new DateRangeQueryDescription(tz.ToLocalTime(new DateTime(summary.Year, summary.Month, 1)),
                                                                                      tz.ToLocalTime(new DateTime(summary.Year, summary.Month, 1).AddMonths(1).AddDays(-1))), null)
                                                    )
                                        where te.Language == acceptLanguages || acceptLanguages.Contains(te.Language)
                                        select EntryFromTextEntry(te)).ToArray());
        }

        private static TextEntry TextEntryFromEntry(Entry entry)
        {
            return null;
        }

        private static TextEntry TextEntryFromComment(Comment entry)
        {
            return null;
        }

        private static Entry EntryFromTextEntry(TextEntry entry)
        {
            return new Entry
            {
                AllowComments = entry.AllowComments.HasValue?entry.AllowComments.Value:false,
                Author = entry.Author.DisplayName,
                Categories = entry.CategoriesAsString,
                Content = entry.Content,
                CreatedUtc = entry.Created,
                Description = entry.Summary,
                EntryId = entry.Id,
                Syndicated = entry.Published.HasValue ? entry.Published.Value : false,
                IsPublic = entry.Published.HasValue ? entry.Published.Value : false,
                Language = entry.Language,
                Title = entry.Title,
                ShowOnFrontPage = entry.Featured.HasValue?entry.Featured.Value:false
            };
        }

        private static Comment CommentFromTextEntry(TextEntry entry)
        {
            return new Comment
            {
                Author = entry.Author.DisplayName,
                AuthorEmail = entry.Author.Email,
                TargetEntryId = new ContextUri(entry.Parent).Id,
                Content = entry.Content,
                CreatedUtc = entry.Created,
                EntryId = new ContextUri(entry.Id).Id,
                IsPublic = entry.Published.GetValueOrDefault(),
                Language = entry.Language,
                ModifiedUtc = entry.LastChange,
            };
        }

        public EntryCollection GetEntriesForCategory(string categoryName, string acceptLanguages)
        {
            IStorageNode storageNode = StorageBus.Current.FindNode(postsUri);
            return new EntryCollection((from entry in SerializationTools<TextEntry>.DeserializeList(
                                                        storageNode.Select(null, postsUri.ToString(), ContextMatch.Exact,
                                                             new TagQueryDescription(categoryName), null))
                                        where entry.Language == null || acceptLanguages.Contains(entry.Language)
                                        orderby entry.Created
                                        select EntryFromTextEntry(entry)).ToArray());
            
        }

        public EntryCollection GetEntriesForUser(string user)
        {
            return null;
        }

        public DateTime[] GetDaysWithEntries(TimeZone tz)
        {
            IStorageNode storageNode = StorageBus.Current.FindNode(postsUri);
            var entries = SerializationTools<PropertyAggregate>.DeserializeList(
                 storageNode.Aggregate(null, postsUri.ToString(), ContextMatch.Exact, "datecreated", null)
                 );
            return (from agg in entries select DateTime.Parse(agg.Value)).ToArray();
        }

        public DayEntry GetDayEntry(DateTime date)
        {
            return new DayEntry
            {
                DateUtc = date,
                Entries = GetEntriesForDay(date, TimeZone.CurrentTimeZone, null, int.MaxValue, int.MaxValue, null),
                DateLocalTime = date.ToLocalTime(),
            };
        }

        public DayExtra GetDayExtra(DateTime date)
        {
            IStorageNode storageNode = StorageBus.Current.FindNode(postsUri);

            var entriesOnDay = SerializationTools<TextEntry>.DeserializeList(
                storageNode.Select(null,
                                    postsUri.ToString(),
                                    ContextMatch.Exact,
                                    new DateRangeQueryDescription(date.Date.ToUniversalTime(), date.Date.AddDays(1).AddMilliseconds(-1)),
                                    null));

            var allComments = new CommentCollection(
                              (from TextEntry post in entriesOnDay
                               from TextEntry comment in SerializationTools<TextEntry>.DeserializeList(
                                                            StorageBus.Current.FindNode(new ContextUri(new ContextUri(post.Id), PathSegmentName.Comments)).Select(null,
                                                                                new ContextUri(new ContextUri(post.Id), PathSegmentName.Comments).ToString(),
                                                                                ContextMatch.Exact,
                                                                                null, null))
                              select CommentFromTextEntry(comment)).ToArray());

            DayExtra extra = new DayExtra();
            extra.Comments.AddRange(allComments);
            return extra;
        }

        public void DeleteEntry(string entryId, CrosspostSiteCollection crosspostSites)
        {
            IStorageNode storageNode = StorageBus.Current.FindNode(postsUri);
            storageNode.Delete(new ContextUri(postsUri, entryId).ToString());
        }

        public EntrySaveState SaveEntry(Entry entryId, params object[] trackingInfos)
        {
            IStorageNode storageNode = StorageBus.Current.FindNode(postsUri);
            storageNode.Add(postsUri.ToString(),
                            SerializationTools<TextEntry>.ToXmlElement(TextEntryFromEntry(entryId)),
                            null);
            return EntrySaveState.Added;
        }

        public CategoryCacheEntryCollection GetCategories()
        {
            IStorageNode storageNode = StorageBus.Current.FindNode(new ContextUri(scopeUri, PathSegmentName.Tags));
            return new CategoryCacheEntryCollection(
                (from PropertyAggregate agg in SerializationTools<PropertyAggregate>.DeserializeList(storageNode.Aggregate(null, postsUri.ToString(), ContextMatch.Exact, "tag", null))
                 select new CategoryCacheEntry
                 {
                     Name = agg.Value,
                     IsPublic = true
                 }).ToArray());
        }

        public void RunActions(object[] actions)
        {

        }

        public void AddTracking(Tracking tracking, params object[] actions)
        {

        }

        public void DeleteTracking(string entryId, string trackingPermalink, TrackingType trackingType)
        {

        }

        public TrackingCollection GetTrackingsFor(string entryId)
        {
            return new TrackingCollection();
        }

        public void AddComment(Comment comment, params object[] actions)
        {
            ContextUri contextUri = new ContextUri(postsUri, comment.TargetEntryId, PathSegmentName.Comments);
            IStorageNode storageNode = StorageBus.Current.FindNode(contextUri);
            
            storageNode.Add(contextUri.ToString(), 
                            SerializationTools<TextEntry>.ToXmlElement(TextEntryFromComment(comment)), 
                            null);
        }

        public Comment GetCommentById(string entryId, string commentId)
        {
            IStorageNode storageNode = StorageBus.Current.FindNode(new ContextUri(postsUri, entryId, PathSegmentName.Comments));
            TextEntry entry = SerializationTools<TextEntry>.Deserialize(storageNode.Get(null, new ContextUri(postsUri, entryId, PathSegmentName.Comments, commentId).ToString(), null));
            if (entry != null)
            {
                return CommentFromTextEntry(entry);
            }
            else
            {
                return null;
            }
        }

        public void ApproveComment(string entryId, string commentId)
        {
            
        }

        public void DeleteComment(string entryId, string commentId)
        {
            IStorageNode storageNode = StorageBus.Current.FindNode(new ContextUri(postsUri, entryId, PathSegmentName.Comments));
            storageNode.Delete(new ContextUri(postsUri, entryId, PathSegmentName.Comments, commentId).ToString());
        }

        public CommentCollection GetCommentsFor(string entryId)
        {
            return new CommentCollection(
                              (from TextEntry comment in SerializationTools<TextEntry>.DeserializeList(
                                                            StorageBus.Current.FindNode(new ContextUri(postsUri, entryId, PathSegmentName.Comments)).Select(null,
                                                                                new ContextUri(postsUri, entryId, PathSegmentName.Comments).ToString(),
                                                                                ContextMatch.Exact,
                                                                                null, null))
                               select CommentFromTextEntry(comment)).ToArray());
        }

        public CommentCollection GetPublicCommentsFor(string entryId)
        {
            return new CommentCollection(
                              (from TextEntry comment in SerializationTools<TextEntry>.DeserializeList(
                                                            StorageBus.Current.FindNode(new ContextUri(postsUri, entryId, PathSegmentName.Comments)).Select(null,
                                                                                new ContextUri(postsUri, entryId, PathSegmentName.Comments).ToString(),
                                                                                ContextMatch.Exact,
                                                                                null, null))
                               where comment.Published == true
                               select CommentFromTextEntry(comment)).ToArray());
        }

        public CommentCollection GetCommentsFor(string entryId, bool allComments)
        {
            return GetCommentsFor(entryId);
        }

        public CommentCollection GetAllComments()
        {
            IStorageNode storageNode = StorageBus.Current.FindNode(postsUri);
            return new CommentCollection(
                              (from TextEntry post in SerializationTools<TextEntry>.DeserializeList(
                                                        storageNode.Select(null,
                                                                            postsUri.ToString(),
                                                                            ContextMatch.Exact,
                                                                            null,
                                                                            null))
                               from TextEntry comment in SerializationTools<TextEntry>.DeserializeList(
                                                            StorageBus.Current.FindNode(new ContextUri(new ContextUri(post.Id), PathSegmentName.Comments)).Select(null,
                                                                                new ContextUri(new ContextUri(post.Id), PathSegmentName.Comments).ToString(),
                                                                                ContextMatch.Exact,
                                                                                null, null))
                               select CommentFromTextEntry(comment)).ToArray());
        }

        public DateTime GetLastEntryUpdate()
        {
            return DateTime.Now;
        }

        public DateTime GetLastCommentUpdate()
        {
            return DateTime.Now;
        }

        public EntryCollection /*IBlogDataService*/ GetEntries(
            DayEntryCollection.CriteriaHandler dayEntryCriteria,
            Predicate<Entry> entryCriteria,
            int maxDays, int maxEntries)
        {
            throw new NotImplementedException();
        }

        public EntryIdCache GetEntryIdCache()
        {
            return null;
        }

        public string AddFile(string entryId, string fileName, string contentType, long contentLength, System.IO.Stream contentData)
        {
            throw new NotImplementedException();
        }

        public string[] GetFileList(string entryId)
        {
            throw new NotImplementedException();
        }

        public void DeleteFiles(string entryId)
        {
            throw new NotImplementedException();
        }
    }
}
